
local registry = ...
local setmetatable,getmetatable,ipairs,unpack = setmetatable,getmetatable,ipairs,unpack

local function magicbuttonfactory(magicmeta)
    return function(a,b)
        local ameta,bmeta = getmetatable(a),getmetatable(b)
        if ameta == magicmeta then
            if bmeta == magicmeta then
                local c = setmetatable({unpack(a)}, magicmeta)
                local x = #a
                for i,v in ipairs(b) do
                    c[x+i] = v
                end
                return c
            end
            return setmetatable({b, unpack(a)}, magicmeta)
        elseif bmeta == magicmeta then
            return setmetatable({a, unpack(b)}, magicmeta)
        else
            return setmetatable({a,b}, magicmeta)
        end
    end
end

local combometa,alternameta

combometa = {
    __index = function(me, query)
        if query == 'down' then
            for _,member in ipairs(me) do
                if not member.down then
                    return false
                end
            end
            return true
        elseif query == 'struck' then
            local onestruck = false
            for _,member in ipairs(me) do
                if not member.down then
                    return false
                end
                onestruck = onestruck or member.struck
            end
            return onestruck
        elseif query == 'released' then
            local onereleased = false
            for _,member in ipairs(me) do
                if member.released then
                    onereleased = true
                elseif not member.down then
                    return false
                end
            end
            return onereleased
        end
    end;
}

alternameta = {
    __index = function(me, query)
        if query == 'down' then
            for _,member in ipairs(me) do
                if member.down then
                    return true
                end
            end
            return false
        elseif query == 'struck' then
            local onestruck = false
            for _,member in ipairs(me) do
                if member.struck then
                    onestruck = true
                elseif member.down then
                    return false
                end
            end
            return onestruck
        elseif query == 'released' then
            local onereleased = false
            for _,member in ipairs(me) do
                if member.released then
                    onereleased = true
                elseif member.down then
                    return false
                end
            end
            return onereleased
        end
    end;
}

local add = magicbuttonfactory(alternameta)
local mul = magicbuttonfactory(combometa)

combometa.__add, combometa.__mul = add, mul
alternameta.__add, alternameta.__mul = add, mul

registry.addbutton, registry.multbutton = add, mul

return true
